//import java.util.HashMap;
import java.util.Iterator;
import java.util.Hashtable;
//import java.lang.Runtime;

/**
 * Abstract, optimal optimizer, extended by all versions
 *  of optimal optimizers.
 * computes results for all boxes, even those with no bits. 
 * @author Ed Hong
 *
 */
public abstract class AbstractOptimalOptimizer extends Optimizer {

        Hashtable<ContextCharacteristicsBox, solutionInfo> allSol; // dynprog store of all solutions
       
        protected class solutionInfo {
            SplitCriteria splitc;
            double cost; 
            
            public solutionInfo(SplitCriteria sc, double c){
                splitc = sc;
                cost = c;
            }
            
            public String toString() {
              return "<" + splitc + "," + cost + ">";
            }
        }

    protected ContextCharacteristicsBox cbstart; // starting box; initialized after
                                           // ccdfile is loaded. 
                                                   
        // recursive dynprog solution. 
    protected abstract solutionInfo solve(ContextCharacteristicsBox cb, double threshold);
        
	
	public AbstractOptimalOptimizer(String ccdFile) {
		super(ccdFile);
                cbstart = ContextCharacteristicsBox.getLargestBox();
                allSol = new Hashtable<ContextCharacteristicsBox, solutionInfo>( );
	}
	
	@Override
	public ContextTreeNode findOptimalContextTree(double threshold) {
		
                // solve to find best cost. 
                solutionInfo best;
                best = solve(cbstart, threshold);
                
                System.out.println("Best: " + best);
                if(FULLDEBUG)System.out.println(allSol);
                
                ContextTreeNode root = new ContextTreeNode(
                            ContextDefinition.getContextDefinition().getAllSplitCriteria(),
                                        new ContextDataCollection(contextData));   
                buildOptimalTree(cbstart,root);

		// dump the content of tree
		if (DEBUG) {
			System.out.println("Optimization tree->");
			dumpContextTreeSplits(root,0);
		}

		// print memory usage.
		Runtime rt = Runtime.getRuntime();
		System.out.println("Max Memory: " + 
				   rt.maxMemory() / 1024.0 / 1024.0 + "M");
		System.out.println("Total Memory: " + 
				   rt.totalMemory() / 1024.0 / 1024.0 + "M");
		System.out.println("Free Memory: " + 
				   rt.freeMemory() / 1024.0 / 1024.0 + "M");

                return root;
                 
                    			
        }
        
        abstract protected void buildOptimalTree(ContextCharacteristicsBox cb, 
                                ContextTreeNode currnode); 
}
